#       results_dialog.py
#       
#       Copyright 2010 Alexey Zotov <alexey.zotov@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

# -*- coding: utf8 -*-

import os
import urllib

from PyQt4 import QtCore
from PyQt4.QtCore import Qt
from PyQt4 import QtGui
from PyKDE4 import plasmascript
from PyKDE4.plasma import Plasma
from PyKDE4 import kdecore
from PyKDE4.kdecore import i18n
from PyKDE4 import kdeui
from PyKDE4.kio import KIO

import logger

LEN_2_LAYOUT = {
    1: [1],
    2: [2],
    3: [3],
    4: [2, 2],
    5: [2, 1, 2],
    6: [3, 3],
    7: [2, 3, 2],
    8: [3, 2, 3],
    9: [3, 3, 3]
}

class ResultsLayout(QtGui.QGraphicsLinearLayout):
    def __init__(self, capacity, parent=None):
        QtGui.QGraphicsLinearLayout.__init__(self, Qt.Vertical, parent)
        if capacity < 1:
            capacity = 1
        elif capacity > 9:
            capacity = 9
        self.capacity = capacity
        self.count = 0
        self.hlayouts = []
        for ind in LEN_2_LAYOUT[capacity]:
            hlayout = QtGui.QGraphicsLinearLayout(self)
            hlayout.setContentsMargins(5, 5, 5, 5)
            hlayout.setSpacing(10)
            hlayout.addStretch()
            self.hlayouts.append(hlayout)
            QtGui.QGraphicsLinearLayout.addItem(self, hlayout)
    
    def addItem(self, item):
        if self.count >= self.capacity:
            return

        count = self.count
        for ind, hlayout in enumerate(self.hlayouts):
            hcapacity = LEN_2_LAYOUT[self.capacity][ind]
            if count < hcapacity:
                hlayout.addItem(item)
                hlayout.addStretch()
                self.count += 1
                break
            else:
                count -= hcapacity

class ResultWidget(QtGui.QGraphicsWidget):
    def __init__(self, applet, result, dialog_ctor, menu_ctor, parent=None,
        flags=Qt.WindowFlags()):

        QtGui.QGraphicsWidget.__init__(self, parent, flags)
        self.applet = applet
        self.result = result
        self.dialog_ctor = dialog_ctor
        self.menu_ctor = menu_ctor
        self.setAcceptHoverEvents(True)
        self.setMinimumSize(170, 100)
        self.thumb = Plasma.Label()
        self.resetPalette = self.thumb.nativeWidget().palette()
        self.set_appearance()
        glayout = QtGui.QGraphicsLinearLayout(Qt.Vertical)
        glayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(glayout)
        self.result['thumbpath'] = os.path.join(
            applet.thumbsdir, self.result['name'])
        if os.path.isfile(self.result['thumbpath']):
            self.set_up_thumb()
        else:
            self.busy = Plasma.BusyWidget()
            self.layout().addItem(self.busy)
            self.applet.download_thumb(
                self.result['thumb'],
                self.result['thumbpath'],
                self.download_thumb_callback
            )

    def set_effect(self, setting):
        effect = QtGui.QGraphicsOpacityEffect()
        effect.setOpacity(
            self.applet.settings['results/%s_opacity' % setting]/100.0)
        self.thumb.setGraphicsEffect(effect)
        if self.applet.settings['results/%s_frame' % setting]:
            palette = QtGui.QPalette(self.thumb.nativeWidget().palette())
            palette.setColor(
                QtGui.QPalette.WindowText,
                QtGui.QColor(self.applet.settings['results/%s_color' % setting])
            )
            self.thumb.nativeWidget().setPalette(palette)

    def set_appearance(self):
        self.thumb.setGraphicsEffect(None)
        self.thumb.nativeWidget().setPalette(self.resetPalette)
        if not self.result['useronly'] and self.result['user']:
            self.set_effect('user')
        if self.result['new']:
            self.set_effect('new')
        if not self.result['urls']:
            if self.result['cached']:
                self.set_effect('cached')
            else:
                self.set_effect('bad_urls')
    
    def update_result(self, result):
        if result['name'] != self.result['name']:
            return
        self.result.update(result)
        self.set_appearance()
        self.set_tooltip()

    @logger.log_exc
    def download_thumb_callback(self, job):
        self.busy.setVisible(False)
        self.layout().removeAt(0)

        if job.error():
            self.applet.notify_error(i18n('Thumb downloading error'))
            return

        self.set_up_thumb()

    def set_up_thumb(self):
        self.qicon = QtGui.QIcon(QtGui.QPixmap(self.result['thumbpath']))
        self.thumb.setMinimumSize(170, 100)
        self.thumb.setText('<img src="%s">' % self.result['thumbpath'])
        self.thumb.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.thumb.nativeWidget().setFrameStyle(QtGui.QFrame.Box)
        self.thumb.nativeWidget().setCursor(
            QtGui.QCursor(Qt.PointingHandCursor))
        self.layout().addItem(self.thumb)
        self.set_tooltip()

    def set_tooltip(self):
        name_parts = self.result['name'].split('_')
        tooltip = Plasma.ToolTipContent()
        tooltip.setImage(self.qicon)
        tooltip.setMainText(name_parts[1])
        tooltip.setSubText(Qt.escape(', '.join(self.result['tags'])))
        Plasma.ToolTipManager.self().setContent(self.thumb, tooltip)

    @logger.log_exc
    def hoverEnterEvent(self, event):
        self.thumb.setScale(1.1)
        self.thumb.setPos(-8.0, -5.0)

    @logger.log_exc
    def hoverLeaveEvent(self, event):
        self.thumb.setScale(1.0)
        self.thumb.setPos(0.0, 0.0)

    @logger.log_exc
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.result_dialog = self.dialog_ctor(self.applet, self.result)
            self.result_dialog.accepted.connect(self.result_dialog_closed)
            self.result_dialog.rejected.connect(self.result_dialog_closed)
            self.result_dialog.show()
        elif event.button() == Qt.RightButton:
            self.result_menu = self.menu_ctor(self.applet, self.result)
            self.result_menu.popup(event.screenPos())

    @logger.log_exc
    def result_dialog_closed(self):
        self.result_dialog.deleteLater()


class ResultsDialog(Plasma.Dialog):
    closed = QtCore.pyqtSignal()

    def __init__(self, params, applet, results, dialog_ctor, menu_ctor,
        parent=None, flags=Qt.Window):

        Plasma.Dialog.__init__(self, parent, flags)
        self.params = params
        self.applet = applet
        self.setWindowIcon(self.applet.qicon)
        self.setWindowTitle(params['title'])
        self.gwidget = QtGui.QGraphicsWidget()
        glayout = QtGui.QGraphicsLinearLayout(Qt.Vertical)
        reload_button = Plasma.ToolButton()
        reload_button.setIcon(kdeui.KIcon('view-refresh'))
        reload_button.clicked.connect(self.reload_clicked)
        caption_label = Plasma.Label()
        caption_label.setText('<b>%s</b>' % params['title'])
        caption_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        close_button = Plasma.ToolButton()
        close_button.setIcon(kdeui.KIcon("window-close"))
        close_button.clicked.connect(self.close)
        caption_layout = QtGui.QGraphicsLinearLayout()
        caption_layout.addItem(reload_button)
        caption_layout.addItem(caption_label)
        caption_layout.addItem(close_button)
        results_layout = ResultsLayout(len(results))
        glayout.addItem(caption_layout)
        glayout.addItem(results_layout)
        self.gwidget.setLayout(glayout)
        self.result_widgets = []
        for result in results:
            result_widget = ResultWidget(
                applet, result, dialog_ctor, menu_ctor)
            self.result_widgets.append(result_widget)
            results_layout.addItem(result_widget)
        applet.containment().corona().addOffscreenWidget(self.gwidget)
        self.setGraphicsWidget(self.gwidget)
        desktop = QtGui.QApplication.desktop()
        screen_number = desktop.screenNumber(self)
        screen_geometry = desktop.screenGeometry(screen_number)
        self.move(
            screen_geometry.width()/2 - self.width()/2,
            screen_geometry.height()/2 - self.height()/2
        )

    def reload_clicked(self):
        self.params['method'](*self.params['args'])

    def update_result(self, result):
        for result_widget in self.result_widgets:
            if result_widget.result['name'] != result['name']:
                continue
            result_widget.update_result(result)
            break

    @logger.log_exc
    def closeEvent(self, event):
        self.closed.emit()
